﻿@page "/user/loginWith2fa"
@using AliasVault.Shared.Models.Enums

<LayoutPageTitle>Two-factor authentication</LayoutPageTitle>

<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">
    Two-factor authentication
</h2>

<ServerValidationErrors @ref="ServerValidationErrors" />

<p class="text-gray-700 dark:text-gray-300 mb-6">Your login is protected with an authenticator app. Enter your authenticator code below.</p>
<div class="w-full max-w-md">
    <EditForm Model="Input" FormName="login-with-2fa" OnValidSubmit="OnValidSubmitAsync" method="post" class="space-y-6">
        <input type="hidden" name="ReturnUrl" value="@ReturnUrl"/>
        <input type="hidden" name="RememberMe" value="@RememberMe"/>
        <DataAnnotationsValidator/>
        <ValidationSummary class="text-red-600 dark:text-red-400" role="alert"/>
        <div>
            <label for="two-factor-code" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Authenticator code</label>
            <InputText @bind-Value="Input.TwoFactorCode" id="two-factor-code" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" autocomplete="off"/>
            <ValidationMessage For="() => Input.TwoFactorCode" class="text-red-600 dark:text-red-400 text-sm mt-1"/>
        </div>
        <div class="flex items-start">
            <div class="flex items-center h-5">
                <InputCheckbox @bind-Value="Input.RememberMachine" id="remember-machine" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-primary-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-primary-600 dark:ring-offset-gray-800"/>
            </div>
            <div class="ml-3 text-sm">
                <label for="remember-machine" class="font-medium text-gray-900 dark:text-white">Remember this machine</label>
            </div>
        </div>
        <button type="submit" class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">Log in</button>
    </EditForm>
</div>
<p class="mt-6 text-sm text-gray-700 dark:text-gray-300">
    Don't have access to your authenticator device? You can
    <a href="user/loginWithRecoveryCode?ReturnUrl=@ReturnUrl" class="text-primary-600 hover:underline dark:text-primary-500">log in with a recovery code</a>.
</p>

@code {
    private AdminUser user = default!;

    [SupplyParameterFromForm]
    private InputModel Input { get; set; } = new();

    [SupplyParameterFromQuery]
    private string? ReturnUrl { get; set; }

    [SupplyParameterFromQuery]
    private bool RememberMe { get; set; }

    /// <inheritdoc />
    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();

        // Ensure the user has gone through the username & password screen first
        user = await SignInManager.GetTwoFactorAuthenticationUserAsync() ??
               throw new InvalidOperationException("Unable to load two-factor authentication user.");
    }

    /// <summary>
    /// Submits the form.
    /// </summary>
    private async Task OnValidSubmitAsync()
    {
        ServerValidationErrors.Clear();

        var authenticatorCode = Input.TwoFactorCode!.Replace(" ", string.Empty).Replace("-", string.Empty);
        var result = await SignInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, RememberMe, Input.RememberMachine);
        var userId = await UserManager.GetUserIdAsync(user);

        if (result.Succeeded)
        {
            await AuthLoggingService.LogAuthEventSuccessAsync(user.UserName!, AuthEventType.TwoFactorAuthentication);
            Logger.LogInformation("User with ID '{UserId}' logged in with 2fa.", userId);
            NavigationService.RedirectTo(ReturnUrl);
        }
        else if (result.IsLockedOut)
        {
            await AuthLoggingService.LogAuthEventFailAsync(user.UserName!, AuthEventType.TwoFactorAuthentication, AuthFailureReason.AccountLocked);
            Logger.LogWarning("User with ID '{UserId}' account locked out.", userId);
            NavigationService.RedirectTo("user/lockout");
        }
        else
        {
            await AuthLoggingService.LogAuthEventFailAsync(user.UserName!, AuthEventType.TwoFactorAuthentication, AuthFailureReason.InvalidTwoFactorCode);
            Logger.LogWarning("Invalid authenticator code entered for user with ID '{UserId}'.", userId);
            ServerValidationErrors.AddError("Error: Invalid authenticator code.");
        }
    }

    private sealed class InputModel
    {
        [Required]
        [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Text)]
        [Display(Name = "Authenticator code")]
        public string? TwoFactorCode { get; set; }

        [Display(Name = "Remember this machine")]
        public bool RememberMachine { get; set; }
    }

}
